package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
	"strings"
)

// Configuration 表示全局配置对象。
type Configuration struct {
	// 提供服务的基础路径。
	Base string
	// 提供服务的绑定地址。
	Listen string
	// HTTPS的绑定地址。
	SSLListen string `json:"ssl_listen"`
	// HTTPS的通信证书。
	SSLCert string `json:"ssl_cert"`
	// HTTPS的通信证书私钥。
	SSLCertKey string `json:"ssl_cert_key"`
	// 读取和写入的超时（秒）
	Timeout int
	// 代理项字典
	Proxies map[string]*ProxyConfigurationElement
}

// ProxyConfigurationElement 表示一个代理配置项
type ProxyConfigurationElement struct {
	Target          string
	PathRewriteRule map[string]string `json:"pathRewrite"`
}

func (cfg *Configuration) String() string {
	return fmt.Sprintf("{ base: %v, listen: %v, ssl_listen: %v, ssl_cert: %v, ssl_cert_key: %v, timeout: %d, proxies: %v }",
		cfg.Base, cfg.Listen, cfg.SSLListen, cfg.SSLCert, cfg.SSLCertKey, cfg.Timeout, cfg.Proxies)
}

func (cfgEle *ProxyConfigurationElement) String() string {
	return fmt.Sprintf("{ target: %v, pathRewrite: %v }", cfgEle.Target, cfgEle.PathRewriteRule)
}

// 判断指定的路径中是否包含了双点号(`..`)
func containsDotDot(v string) bool {
	if !strings.Contains(v, "..") {
		return false
	}
	for _, ent := range strings.FieldsFunc(v, func(r rune) bool { return r == '/' || r == '\\' }) {
		if ent == ".." {
			return true
		}
	}
	return false
}

// 从`Accpet-Language`当中解析得到`Locale`。
func parseLocale(acceptLanguage string) string {
	acceptLanguage = strings.TrimSpace(acceptLanguage)
	if acceptLanguage == "" {
		return ""
	}

	p1 := strings.IndexAny(acceptLanguage, ",;")
	if p1 == -1 {
		return strings.ToLower(acceptLanguage)
	}

	return acceptLanguage[:p1]
}

// 将错误对象转化为对应的HTTP响应。
func toHTTPError(err error) (msg string, httpStatus int) {
	if os.IsNotExist(err) {
		return "Not found", http.StatusNotFound
	}
	if os.IsPermission(err) {
		return "Forbidden", http.StatusForbidden
	}
	// Default:
	return "Internal Server Error", http.StatusInternalServerError
}

// 输出HTTP响应日志。
func httpLog(method, path, target string) {
	target = strings.TrimSpace(target)

	log.Printf("%s %s => %s", method, path, target)
}
